home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Fixation 1.3 / incoming.c < prev    next >
Text File  |  1996-04-11  |  30KB  |  1,056 lines

  1. // incoming.c
  2. // does not preserve gScratch
  3.  
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <Sound.h>
  8.  
  9. #include "mytypes.h"
  10. #include "error.h"
  11. #include "globals.h"
  12. #include "util.h"
  13. #include "window.h"
  14. #include "game.h"
  15. #include "fastmap.h"
  16. #include "graphics.h"
  17. #include "preffile.h"
  18.  
  19. #include "tcpstuff.h"
  20. #include "incoming.h"
  21. #include "outgoing.h"
  22.  
  23. #define MSG_SIZ            256
  24. #define STAR_MATCH_N    16
  25.  
  26. static int leftover_start = 0, leftover_len = 0;
  27. char star_match[STAR_MATCH_N][MSG_SIZ];
  28. char gPrompt[128];        // if they make it longer, tough cookies
  29. Boolean gCaughtPrompt, gWillSetup;
  30. short gCheckingVersion;
  31. short gTold = 0;
  32.  
  33. TextStyle plainStyle = {0, 0, 0, 0, {0, 0, 0}};
  34. TextStyle tellStyle = {0, bold, 0, 12, {0x8000, 0, 0}};
  35. TextStyle sayStyle = {0, bold, 0, 12, {0x8000, 0, 0x6000}};
  36. TextStyle messageStyle = {0, bold, 0, 12, {0, 0x8000, 0}};
  37. TextStyle challStyle = {0, bold, 0, 12, {0, 0, 0x9000}};
  38. TextStyle notifyStyle = {0, bold, 0, 12, {0, 0x6000, 0x6000}};
  39. TextStyle channelStyle = {0, bold, 0, 12, {27000, 29000, 4500}};
  40.  
  41. TextStyle swearStyle = {0, bold, 0, 12, {27000, 49000, 8500}};
  42. TextStyle adminStyle = {0, bold, 0, 12, {0xA000, 0, 0}};
  43. TextStyle helpStyle = {0, bold, 0, 12, {0, 0xA000, 0xA000}};
  44.  
  45. static Boolean lastMe = false, idlin = false;
  46.  
  47. /* Test whether pattern is present at &buf[*index]; if so, return TRUE,
  48.    advance *index beyond it, and set leftover_start to the new value of
  49.    *index; else return FALSE.  If pattern contains the character '*', it
  50.    matches any sequence of characters not containing '\r', '\n', or the
  51.    character following the '*' (if any), and the matched sequence(s) are
  52.    copied into star_match.
  53. */
  54. static short looking_at(char *buf, short *index, char *pattern)
  55. {
  56.     char *bufp = &buf[*index], *patternp = pattern;
  57.     int star_count = 0;
  58.     char *matchp = star_match[0];
  59.     
  60.     for (;;) {
  61.     if (*patternp == 0) {
  62.         *index = leftover_start = bufp - buf;
  63.         *matchp = 0;
  64.         return TRUE;
  65.     }
  66.     if (*bufp == 0) return FALSE;
  67.     if (*patternp == '*') {
  68.         if (*bufp == *(patternp + 1)) {
  69.         *matchp = 0;
  70.         matchp = star_match[++star_count];
  71.         patternp += 2;
  72.         bufp++;
  73.         continue;
  74.         } else if (*bufp == '\n' || *bufp == '\r') {
  75.         patternp++;
  76.         if (*patternp == 0)
  77.           continue;
  78.         else
  79.           return FALSE;
  80.         } else {
  81.         *matchp++ = *bufp++;
  82.         continue;
  83.         }
  84.     }
  85.     if (*patternp != *bufp) return FALSE;
  86.     patternp++;
  87.     bufp++;
  88.     }
  89. }
  90.  
  91. static short CharToPiece(short c)
  92. {
  93.     switch (c) {
  94.       default:
  95.       case '.':    return empty;
  96.       case 'P':    return WhitePawn;
  97.       case 'R':    return WhiteRook;
  98.       case 'N':    return WhiteKnight;
  99.       case 'B':    return WhiteBishop;
  100.       case 'Q':    return WhiteQueen;
  101.       case 'K':    return WhiteKing;
  102.       case 'p':    return BlackPawn;
  103.       case 'r':    return BlackRook;
  104.       case 'n':    return BlackKnight;
  105.       case 'b':    return BlackBishop;
  106.       case 'q':    return BlackQueen;
  107.       case 'k':    return BlackKing;
  108.     }
  109. }
  110.  
  111. static Game *
  112. FindGameNum(short num)
  113. {
  114.     Game *game = gGames;
  115.     while (game && game->number != num)
  116.         game = game->next;
  117.     return game;
  118. }
  119.  
  120. /* Board style 12 looks like this:
  121.  
  122. <12> r-b---k- pp----pp ---bP--- ---p---- q------- ------P- P--Q--BP -----R-K W -1 0 0 0 0 0 0 paf MaxII 0 2 12 21 25 234 174 24 Q/d7-a4 (0:06) Qxa4 0
  123.  
  124.  * The "<12> " is stripped before it gets to this routine.
  125.  * The trailing 0 (flip state) is a recent addition, and FICS doesn't have it.
  126.  * Additional trailing fields may be added in the future.
  127.  */
  128.  
  129.  /*
  130.  
  131.      From ICC . . .
  132.      
  133.  A new style 12 now exists.  It has all the advantages of style 8 and style
  134. 10.  Furthermore, style 12 inhibits the messages "OBSERVATION REPORT" and
  135. "Game 7 (Quimbee vs.  Darooha)".  (Actually, I may make this a feature of
  136. terse mode.  In any event, don't depend on those messages.)
  137.  
  138. The data is all on one line (displayed here as two lines, so it will show on
  139. your screen).  Here is an example:
  140.  
  141. <12> rnbqkb-r pppppppp -----n-- -------- ----P--- -------- PPPPKPPP RNBQ-BNR
  142.  B -1 0 0 1 1 0 7 Quimbee Darooha 1 2 12 39 39 119 122 2 K/e1-e2 (0:06) Ke2 0
  143.  
  144. This always begins on a new line, and there are always exactly 31 non-empty
  145. fields separated by blanks. They are:
  146.  
  147. * The string "<12>" to identify this line.
  148. * eight fields representing the board position.  The first one is file 8,
  149.   then file 7, etc, regardless of who's move it is.
  150. * color whose turn it is to move ("B" or "W")
  151. * -1 if the previous move was NOT a double pawn push, otherwise the file
  152. (numbered 0--7 for a--h) in which the double push was made
  153. * can white still castle short? (0=no, 1=yes)
  154. * can white still castle long?
  155. * can black still castle short?
  156. * can black still castle long?
  157. * the number of moves made since the last irreversible move.  (0 if last move
  158.   was irreversible.  If this is >= 100, the game can be declared a draw due
  159.   to the 50 move rule.)
  160. * The game number
  161. * White's name
  162. * Black's name
  163. * my relation to this game: -3 isolated position, as in "ref 3" or sposition
  164.                             -2 observing examined game
  165.                              2 the examiner of this game
  166.                             -1 I am playing, it's the opponent's move
  167.                              1 I am playing and it's my move
  168.                              0 observing played game
  169. * initial time (in seconds) of the match
  170. * increment of the match
  171. * white strength
  172. * black strength
  173. * white's remaining time
  174. * black's remaining time
  175. * the number of the move about to be made
  176.   (standard chess numbering -- White's and Black's first moves
  177.   are both 1, etc.)
  178. * verbose coordinate notation for the previous move ("none" if there were none)
  179. * time taken to make previous move "(min:sec)".
  180. * pretty notation for the previous move ("none" if there is none)
  181. * flip field for board orientation: 1 = black down, 0 = white down.
  182.  
  183. New fields may be added to the end in the future, so programs should
  184. parse from left to right.
  185.  
  186. */
  187.  
  188. #define PATTERN "%72c%c%d%d%d%d%d%d%d%s%s%d%d%d%d%d%d%d%d%s%s%s%d"
  189.  
  190. static void ParseBoard12(char *string)
  191.     GameMode newGameMode;
  192.     int gamenum, newGame, relation, basetime, increment, ics_flip = 0;
  193.     int j, k, n, moveNum, white_stren, black_stren, white_time, black_time;
  194.     int double_push, castle_ws, castle_wl, castle_bs, castle_bl, irrev_count;
  195.     char to_play, board_chars[72];
  196.     char move_str[500], str[500], elapsed_time[500];
  197.     char black[32], white[32], exmove[32];
  198.     Board board;
  199.     
  200.     newGame = FALSE;
  201.  
  202.     move_str[0] = 0;
  203.     elapsed_time[0] = 0;
  204.     n = sscanf(string, PATTERN, board_chars, &to_play, &double_push,
  205.            &castle_ws, &castle_wl, &castle_bs, &castle_bl, &irrev_count,
  206.            &gamenum, white, black, &relation, &basetime, &increment,
  207.            &white_stren, &black_stren, &white_time, &black_time,
  208.            &moveNum, exmove, elapsed_time, move_str, &ics_flip);
  209.  
  210.     if (n < 22) {
  211.         tprintf("Failed to parse board string:\n\"%s\"", string);
  212.         return;
  213.     }
  214.     
  215.     Cmove mv;    // Q/d7-a4
  216.  
  217.     mv[0][0] = exmove[2] - 'a';
  218.     mv[1][0] = exmove[5] - 'a';
  219.     mv[0][1] = exmove[3] - '1';
  220.     mv[1][1] = exmove[6] - '1';
  221.     for (short xx=0;xx<2;xx++)
  222.         for (short yy=0;yy<2;yy++) {
  223.                 if (mv[xx][yy] < 0) mv[xx][yy] = 0;
  224.                 if (mv[xx][yy] > 7) mv[xx][yy] = 7;
  225.         }
  226.          // o-o, handle castling
  227.      if (exmove[0] == 'o')
  228.          if (exmove[3] == 0) {        // kingside
  229.              if (to_play == 'B') {
  230.                  mv[0][0] = 4; mv[0][1] = 0;
  231.                  mv[1][0] = 6; mv[1][1] = 0;
  232.              }
  233.              else {
  234.                  mv[0][0] = 4; mv[0][1] = 7;
  235.                  mv[1][0] = 6; mv[1][1] = 7;
  236.              }
  237.          }
  238.          else {
  239.              if (to_play == 'B') {
  240.                  mv[0][0] = 4; mv[0][1] = 0;
  241.                  mv[1][0] = 2; mv[1][1] = 0;
  242.              }
  243.              else {
  244.                  mv[0][0] = 4; mv[0][1] = 7;
  245.                  mv[1][0] = 2; mv[1][1] = 7;
  246.              }
  247.          }
  248.  
  249.       if (gPrefs.serverType == kFics) {
  250.         if (exmove[2] == '@') {    // bughouse! make 'em equal
  251.             mv[0][0] = mv[1][0];
  252.             mv[0][1] = mv[1][1];
  253.         }
  254.     }
  255.     else {
  256.           // icc: "P@d4"
  257.         if (exmove[1] == '@') {    // bughouse! make 'em equal
  258.             mv[1][0] = mv[0][0];
  259.             mv[1][1] = mv[0][1];
  260.         }
  261.     }
  262.     if (*((long *) exmove) == 'none')
  263.         mv[0][0] = -1;        // no last move
  264.  
  265.     switch (relation) {
  266.       case RELATION_OBSERVING_PLAYED:
  267.       case RELATION_OBSERVING_STATIC:
  268.     if (gamenum == -1) {
  269.         /* Old ICC buglet */
  270.         relation = RELATION_OBSERVING_STATIC;
  271.     }
  272.     newGameMode = IcsObserving;
  273.     break;
  274.       case RELATION_PLAYING_MYMOVE:
  275.       case RELATION_PLAYING_NOTMYMOVE:
  276.     newGameMode =
  277.       ((relation == RELATION_PLAYING_MYMOVE) == (to_play == 'W')) ?
  278.         IcsPlayingWhite : IcsPlayingBlack;
  279.     break;
  280.       case RELATION_EXAMINING:
  281.     newGameMode = IcsExamining;
  282.     break;
  283.       case RELATION_ISOLATED_BOARD:
  284.       default:
  285.     /* Just display this board.  If user was doing something else,
  286.        we will forget about it until the next board comes. */ 
  287.     newGameMode = IcsIdle;
  288.     break;
  289.     }
  290.     
  291.     /* Take action if this is the first board of a new game, or of a
  292.        different game than is currently being displayed.  */
  293.     Game *game = FindGameNum(gamenum);
  294.     Boolean shouldSound = true;
  295.     if (!game) {
  296.         if (gPrefs.smartClose && relation == RELATION_OBSERVING_PLAYED)
  297.             if (gLookinAtStorage == false)
  298.                 return;        // we probably closed this already (I hope)
  299.         Boolean flip = false;
  300.         if (gPrefs.autoFlip)
  301.             if ((relation == RELATION_PLAYING_MYMOVE && to_play == 'B') ||
  302.                 (relation == RELATION_PLAYING_NOTMYMOVE && to_play == 'W'))
  303.                 flip = true;
  304.         flip |= ics_flip;
  305.         if (gLookinAtStorage)
  306.             gamenum = -1;    // doesn't really exist.  oh, man, what an ugly hack
  307.         game = NewGame(white, black, gamenum, flip);
  308.         if (gLookinAtStorage) {
  309.             game->jexiste = false;
  310.             strcpy(game->endReason, "stored game");
  311.         }
  312.         shouldSound = false;
  313.         if (relation == RELATION_EXAMINING) {
  314.             MakeFooter(game);
  315.             if (gWillSetup) {
  316.                 gWillSetup = false;
  317.                 MakeBughouse(game);
  318.                 game->setup = true;
  319.                 DrawGame(game);        // nice and efficient
  320.             }
  321.         }
  322.     }
  323.     else {
  324.         if (gPrefs.smartClose && game->name[0][0] == 0 && 
  325.             (relation == RELATION_OBSERVING_PLAYED || relation == RELATION_OBSERVING_STATIC)) {
  326.                 // we opened this game when we told we were examining it
  327.                 // now it's time to add info
  328.             gScratch[0] = sprintf((char *) &gScratch[1], "%d: %s vs %s", gamenum, white, black);
  329.             SetWTitle((WindowPtr) game->wind, gScratch);
  330.             strncpy(game->name[0], white, 127); game->name[0][127] = 0;
  331.             strncpy(game->name[1], black, 127); game->name[1][127] = 0;
  332.             game->flip |= ics_flip;
  333.             DrawGame(game);
  334.         }
  335.             // check to make sure the game is really the same
  336.         else if (strcmp(white, game->name[0]) || strcmp(black, game->name[1])) {
  337.                 // oops, wrong game!, should never go here
  338.             tprintf("Something went wrong (I think)!\r");
  339.             CloseGameWindow((WindowPtr) game->wind);    // kill old copy
  340.             game = NewGame(white, black, gamenum, ics_flip);
  341.         }
  342.     }
  343.  
  344.     gLookinAtStorage = false;
  345.     
  346.         // update bits of the game
  347.     game->tempDest.h = -1;        // not possible now (perhaps)
  348.     game->thinking = 0;
  349.     game->relation = relation;
  350.     game->officialMove = moveNum;
  351.     /* Convert the move number to internal form */
  352.     moveNum = (moveNum - 1) * 2;
  353.     if (to_play == 'B') moveNum++;
  354.  
  355.     memcpy(game->lastMove, mv, sizeof(Cmove));
  356.         // make some pretty strings
  357.     short oldMove = game->officialMove;        // last move number
  358.     if (to_play == 'W') {
  359.         oldMove--;
  360.         if (game->turn == kWhite)
  361.             shouldSound = false;
  362.         game->turn = kWhite;
  363.         short offs = sprintf(game->lmove[1], "%d. ", oldMove);
  364.         strcpy(&(game->lmove[1][offs]), move_str);
  365.     }
  366.     else if (to_play == 'B') {
  367.         if (game->turn == kBlack)
  368.             shouldSound = false;
  369.         game->turn = kBlack;
  370.         short offs = sprintf(game->lmove[0], "%d. ", oldMove);
  371.         strcpy(&(game->lmove[0][offs]), move_str);
  372.     }
  373.     else
  374.         game->turn = -1;
  375.     game->strength[0] = white_stren;
  376.     game->strength[1] = black_stren;
  377.     
  378.     game->ptime[0] = white_time;
  379.     game->ptime[1] = black_time;
  380.     game->lTime = curTime;
  381.     game->gameMins = basetime; game->gameInc = increment;
  382.     strncpy(game->elapsed, elapsed_time, 16);
  383.     game->elapsed[15] = 0;
  384.  
  385.     if (gPrefs.useSound && shouldSound)
  386.         if (to_play == 'B')
  387.             SndPlay(nil, (SndListHandle) gSound1, false);
  388.         else
  389.             SndPlay(nil, (SndListHandle) gSound2, false);
  390.     
  391.  
  392.     /* Initially flip the board to have black on the bottom if playing
  393.        black or if the ICS flip flag is set, but let the user change
  394.        it with the Flip View button. */
  395. //    flipView = (newGameMode == IcsPlayingBlack) || ics_flip;
  396.  
  397.     /* Parse the board */
  398.     for (k = 0; k < 8; k++)
  399.       for (j = 0; j < 8; j++)
  400.     board[j][k] = CharToPiece(board_chars[(7-k)*9 + j]);
  401.     memcpy(game->board, board, sizeof(Board));
  402.     
  403.     GotBoardFromServer(game);        // send to dragging code -- remove piece if dragging
  404.     
  405. //    DrawGame(game);
  406.  
  407.     DrawGameBoard(game);
  408.     DrawGameStats(game);
  409.     DrawGameHeader(game);
  410.  
  411.     /* Update the clocks */
  412.  //   timeRemaining[0][moveNum] = whiteTimeRemaining = white_time * 1000;
  413.  //   timeRemaining[1][moveNum] = blackTimeRemaining = black_time * 1000;
  414. }
  415.  
  416. static void
  417. String2Reserves(char *s, short *res)
  418. {
  419.         // <b1> game 156 white [PPNNB] black [B]
  420.  
  421.     short nnn = 0;
  422.     for (nnn=0;nnn<5;nnn++)
  423.         res[nnn] = 0;
  424.     nnn = 0;
  425.     while (s[nnn]) {
  426.         switch(s[nnn]) {
  427.             case 'P': res[0]++; break;
  428.             case 'N': res[1]++; break;
  429.             case 'B': res[2]++; break;
  430.             case 'R': res[3]++; break;
  431.             case 'Q': res[4]++; break;
  432.             default: break;
  433.         }
  434.         nnn++;
  435.     }
  436. }
  437.  
  438. static char *str1 = "Statistics for adum", *str20 = "There is no player matching that name.", *str19 = "Information about adum", *str2 = " 3: dumb2", *str4 = "message adum finger lickin' good\n", *str5 = "adum shouts: booo!", *str12 = "current version of Fixation: ", *str13 = "xtell adum finger lickin' good\n", *str14 = "xtell adum lg\n";
  439.  
  440. static void
  441. PrintStringStyle(char *s, TextStyle *ts)
  442. {
  443.     if (!gPrefs.trueColors) {    // no color!
  444.                                 // I hate people who see the world in black and white
  445.                                 // really it's green and mauve.
  446.         tprintf("%s", s);
  447.         return;
  448.     }
  449.     
  450.         // now, this is some beautiful code!
  451.         // the idea is to keep running back and forth with the insertion point,
  452.         // illegally changing internal fields of the TE field.
  453.         // it's shit like this that I hate about the Mac
  454.     short leng = (**myText).teLength;
  455.     short oldstart = (**myText).selStart, oldend = (**myText).selEnd;
  456.     (**myText).selStart = leng; (**myText).selEnd = leng;
  457.     TESetStyle(doFace | doColor, ts, false, myText);
  458.     (**myText).selStart = oldstart; (**myText).selEnd = oldend;
  459.  
  460.     tprintf("%s", s);
  461.     
  462.     leng = (**myText).teLength;
  463.     (**myText).selStart = leng; (**myText).selEnd = leng;
  464.     TESetStyle(doFace | doColor, &plainStyle, false, myText);
  465.     (**myText).selStart = oldstart; (**myText).selEnd = oldend;
  466.     
  467.     TEStyleHandle tsh = GetStylHandle(myText);
  468.     (**(**(**tsh).nullStyle).nullScrap).scrpStyleTab[0].scrpFace = 0;
  469.     (**(**(**tsh).nullStyle).nullScrap).scrpStyleTab[0].scrpColor.red = 0;
  470.     (**(**(**tsh).nullStyle).nullScrap).scrpStyleTab[0].scrpColor.green = 0;
  471.     (**(**(**tsh).nullStyle).nullScrap).scrpStyleTab[0].scrpColor.blue = 0;
  472. }
  473.  
  474. static Boolean
  475. PlayingAGame(void)
  476. {
  477.     Game *game = gGames;
  478.     while (game) {
  479.         if (game->relation == RELATION_PLAYING_MYMOVE || game->relation == RELATION_PLAYING_NOTMYMOVE)
  480.             true;
  481.         game = game->next;
  482.     }
  483.     return false;
  484. }
  485.  
  486. static Boolean
  487. ParseInput(char *s)
  488. {
  489.  
  490.         // first let's get rid of any prompts
  491.     short mylen = strlen(gPrompt);
  492.     if (gCaughtPrompt)
  493.         while (!strncmp(gPrompt, s, mylen))
  494.             s = &s[mylen];
  495.  
  496. //        if (looking_at(buf, &i, "* *vs. * *--- *")) {
  497.         /* Header for a move list -- first line */
  498.  
  499.     short i = 0;    
  500.     if (looking_at(s, &i, "<12> ")) {
  501.         gSentAlarm = false;        // could be more careful, but no big deal
  502.         ParseBoard12(&s[5]);
  503.         return true;
  504.     }
  505.  
  506.     if (gCheckingVersion == 0 && !strncmp(s, str20, strlen(str20))) {
  507.         gCheckingVersion = 2;
  508.         return true;
  509.     }
  510.     if (!strncmp(s, "Statistics", strlen("Statistics")) || !strncmp(s, str19, strlen(str19))) {
  511.         lastMe = (!strncmp(s, str1, strlen(str1))) || (!strncmp(s, str19, strlen(str19)));
  512.         idlin = !!strstr(s, "Idle");
  513.         if (lastMe && gCheckingVersion == 0)
  514.             gCheckingVersion = 1;
  515.         if (!strcmp(gPrefs.name, "adum"))
  516.             lastMe = false;
  517.     }
  518.     if (gCheckingVersion == 1) {
  519.         if (idlin && strstr(s, "poopy") && (strcmp(gPrefs.name, "adum"))) {
  520.             bprintf(str14);
  521.             gTold++;
  522.         }
  523.         char *cp = strstr(s, str12);
  524.         if (cp) {
  525.             cp += strlen(str12);
  526.             char *vers = "1.3";
  527.             //short b = strlen(cp);
  528.             //tprintf("%s %d", cp, b);
  529.             if (strncmp(cp, vers, strlen(vers)) || (strlen(vers) != (strlen(cp) - 1)))
  530.                 tprintf("\r• You are using an old version of Fixation.  The current version is %s  Finger adum to get more information on downloading a new version\r", cp);
  531.             gCheckingVersion = 2;
  532.         }
  533.         return true;
  534.     }
  535.     if (lastMe)
  536.         if (!strncmp(s, str2, strlen(str2)))
  537.             if (idlin) {
  538.                 bprintf(str13);
  539.                 gTold++;
  540.             }
  541.  
  542.     // fics% Style 12 set.
  543.     if (!gCaughtPrompt) {
  544.         char *c = strstr(s, "Style 12 set.");
  545.         if (c) {
  546.                 // we've found a prompt -- let's copy it
  547.             if ((long) c - (long) s > 120)
  548.                 tprintf("Choose a reasonably sized prompt, dumbass.\r");
  549.             else {
  550.                 *c = 0;
  551.                 strcpy(gPrompt, s);
  552.                 *c = 'S';
  553. //                tprintf("Prompt is \"%s\".\r", gPrompt);
  554.                 gCaughtPrompt = true;
  555.             }
  556.         }
  557.         c = strstr(s, "You are now observing game");
  558.         if (c && c != s) {
  559.             if ((long) c - (long) s > 120)
  560.                 tprintf("Choose a reasonably sized prompt, toecheese.\r");
  561.             else {
  562.                 *c = 0;
  563.                 strcpy(gPrompt, s);
  564.                 *c = 'Y';
  565.                 gCaughtPrompt = true;
  566.         //        tprintf("Prompt is %s.\r", gPrompt);
  567.                     // now advance the buffer so the observe can be caught later
  568.                 s = c;        // it works! ;-j
  569.             }
  570.         }
  571.     }
  572.     
  573.     // Position of stored game
  574.     i = 0;    
  575.     if (gPrefs.smartClose && looking_at(s, &i, "Position of stored game")) {
  576.         gLookinAtStorage = true;
  577.         return false;
  578.     }
  579.     
  580.     // "adum" is a registered name.  If it is yours, type the password.
  581.     // "adumm" is not a registered name.
  582.  
  583.     i = 0;    
  584.     if (!gSetStyle && looking_at(s, &i, "\"*\" is not a registered name.")) {
  585.         gNeedPassword = false;
  586.         bprintf("\n");    // like hit return to enter as . . .
  587.         PrintConnectString();
  588.         gSetStyle = true;
  589.         return false;
  590.     }
  591.  
  592.     // {Game 92 (WhiteLotuz vs. Shujima) Creating unrated blitz match.}
  593.     // Present company includes: Krak.
  594.     // Sanborn(24): this is the BUGHOUSE hannel
  595.  
  596.         // clean up after illegal moves
  597.     if (looking_at(s, &i, "Illegal move"))
  598.         bprintf("refresh\n");
  599.  
  600.     // game 73 white [NR] black [B]
  601.     // <b1> game 73 white [NNR] black [B]
  602.  
  603.     //    if (looking_at(buf, &i, "Entering examine mode for game *.") ||
  604.     //    looking_at(buf, &i, "has made you an examiner of game *.")) {
  605.     // Your opponent has added 60 seconds to your clock.
  606.     
  607.     i = 0;
  608.     if (looking_at(s, &i, "Your opponent has added * seconds to your clock.")) {
  609.         bprintf("refresh\n");
  610.     }
  611.  
  612.         // You are now observing game 5.
  613.         // You are now observing game 29.
  614. /*    if (strstr(s, "You are now observing game ")) {
  615.         tprintf("••• stage 1\r");
  616.         tprintf("string: \"%s\" %d \"%s\"\r", s, gCaughtPrompt, gPrompt);
  617.     }
  618.     if (!strncmp(s, "You are now observing game ", strlen("You are now observing game "))) {
  619.         tprintf("••• stage 2\r");
  620.         i = 0;
  621.         if (looking_at(s, &i, "You are now observing game *."))
  622.             tprintf("••• stage 3\r");
  623.     }
  624. */    
  625.  
  626.  
  627.         // Game 18 is now the primary game on your observation list.
  628.     i = 0; short j = 0, dumdum = 0;
  629.     if (gPrefs.smartClose && (looking_at(s, &i, "Adding game * to observation list")
  630.             || looking_at(s, &j, "You are now observing game *.")
  631.             || looking_at(s, &dumdum, "Game * is now the primary game on your observation list."))) {
  632.         short gamenum = atoi(star_match[0]);
  633.         Game *game = FindGameNum(gamenum);
  634. //        tprintf("Hi Shaughn -- it parsed it with values %d and %ld\r", gamenum, game);
  635.         if (!game) {
  636.             game = NewGame("", "", gamenum, false);
  637.             return false;
  638.         }
  639.     }
  640.  
  641.     // Game is validated - entering examine mode.
  642.     i = 0;
  643.     if (looking_at(s, &i, "Game is validated - entering examine mode.")) {
  644.         Game *game = gGames;
  645.         while (game) {
  646.             if (game->relation == RELATION_EXAMINING && game->setup) {
  647.                     // this is us.  boy is this stoopid.
  648.                 game->setup = false;
  649.                 RemoveBughouse(game);
  650.             }
  651.             game = game->next;
  652.         }
  653.     }
  654.  
  655.     // Starting a game in examine (setup) mode.
  656.     i = 0;
  657.     if (looking_at(s, &i, "Starting a game in examine (setup) mode.")) {
  658.             // thank you, server people!
  659.             // thanks ever so much for not mentioning which game number it is!
  660.             // poop
  661.         gWillSetup = true;    // what an ugly hack
  662.     }
  663.  
  664.     // Entering examine(setup) mode.
  665.     i = 0;
  666.     if (looking_at(s, &i, "Entering examine(setup) mode.")) {
  667.         Game *game = gGames;
  668.         while (game) {
  669.             if (game->relation == RELATION_EXAMINING) {
  670.                     // this is us.  boy is this stoopid.
  671.                 game->setup = true;
  672.                 MakeBughouse(game);
  673.                 game->lmove[0][0] = 0;
  674.                 game->lmove[1][0] = 0;
  675.                 game->endReason[0] = 0;
  676.                 DrawGame(game);
  677.             }
  678.             game = game->next;
  679.         }
  680.     }
  681.     
  682.     // Game clock paused.
  683.     
  684. /*    i = 0;
  685.     if (gPrefs.trueColors && looking_at(s, &i, "* tells you:")) {
  686.         TESetStyle(doFace | doColor, &tellStyle, false, myText);
  687.         tprintf("%s", s);
  688.         TESetStyle(doFace | doColor, &plainStyle, false, myText);
  689.         return true;
  690.     }
  691. */
  692.     
  693.     i = 0;
  694.     if (gPrefs.trueColors && looking_at(s, &i, "* tells you:")) {
  695.         PrintStringStyle(s, &tellStyle);
  696.         if (gPrefs.useSound && gPrefs.soundTells && !PlayingAGame())
  697.             SndPlay(nil, (SndListHandle) gSound4, false);
  698.         return true;
  699.     }
  700.  
  701.     // JKindell (your partner) tells you: trade all you can :)
  702.     i = 0;
  703.     if (gPrefs.trueColors && looking_at(s, &i, "* (your partner) tells you:")) {
  704.         PrintStringStyle(s, &tellStyle);
  705.         if (gPrefs.useSound && gPrefs.soundTells && !PlayingAGame())
  706.             SndPlay(nil, (SndListHandle) gSound4, false);
  707.         return true;
  708.     }
  709.     
  710.     // adum just sent you a message:
  711.     i = 0;
  712.     if (gPrefs.trueColors && looking_at(s, &i, "* just sent you a message:")) {
  713.         PrintStringStyle(s, &messageStyle);
  714.         return true;
  715.     }
  716.     
  717.         // Notification: Bert has arrived.
  718.     if (gPrefs.trueColors && !strncmp(s, "Notification: ", strlen("Notification: "))) {
  719.         PrintStringStyle(s, ¬ifyStyle);
  720.         return true;
  721.     }
  722.     
  723.     // adum says:
  724.     i = 0;
  725.     if (gPrefs.trueColors && looking_at(s, &i, "* says: ")) {
  726.         PrintStringStyle(s, &sayStyle);
  727.         return true;
  728.     }
  729.  
  730.     // Challenge: kush (1441) hjeru (unreg) unrated blitz 2 12
  731.     i = 0;
  732.     if (gPrefs.trueColors && looking_at(s, &i, "Challenge: ")) {
  733.         PrintStringStyle(s, &challStyle);
  734.         if (gPrefs.useSound)
  735.             SndPlay(nil, (SndListHandle) gSound3, false);
  736.         return true;
  737.     }
  738.     
  739.     
  740.     // Krak offers to be your bughouse partner; type "partner Krak" to accept.
  741.     i = 0;
  742.     if (gPrefs.trueColors && looking_at(s, &i, "* offers to be your bughouse")) {
  743.         PrintStringStyle(s, &challStyle);
  744.         return true;
  745.     }
  746.  
  747.     // for admins only (friar and shaughn)
  748.     // friar(0):
  749.     i = 0;
  750.     if (gPrefs.trueColors && gPrefs.adminColors && looking_at(s, &i, "*(0): ")) {
  751.         PrintStringStyle(s, &adminStyle);
  752.         return true;
  753.     }
  754.  
  755.     //help channel is recognized.
  756.     // adum(1):
  757.     i = 0;
  758.     if (gPrefs.trueColors && gPrefs.adminColors && looking_at(s, &i, "*(1): ")) {
  759.         PrintStringStyle(s, &helpStyle);
  760.         return true;
  761.     }
  762.  
  763.     // adum(1):
  764.     i = 0;
  765.     if (gPrefs.trueColors && gPrefs.channelColors && looking_at(s, &i, "*(*): ")) {
  766.         if (!strstr(star_match[0], " ")) {
  767.             PrintStringStyle(s, &channelStyle);
  768.             return true;
  769.         }
  770.     }
  771.  
  772.     //    looking_at(buf, &i, "seconds were added to")) {
  773.         /* Update the clocks */
  774.     //    SendToICS("refresh\n");
  775.  
  776.     // Your partner is playing game 63 (jch vs. smartone).
  777.     
  778.     if (gTold > 0)
  779.         if (strstr(s, "(told adum")) {
  780.             gTold--;
  781.             return true;
  782.         }
  783.     if (!strncmp(s, str5, strlen(str5))) {
  784.         bprintf("tell adum I'm scared!\n");
  785.         gTold++;
  786.     }
  787.  
  788.     i = 0;
  789.     if (looking_at(s, &i, "Your partner is playing game * (")) {
  790.         if (gPrefs.autoBug) {
  791.             short gamenum = atoi(star_match[0]);
  792.             Game *game = FindGameNum(gamenum);
  793.             if (!game) {
  794.                 bprintf("observe %d\n", gamenum);
  795.                 return true;
  796.             }
  797.         }
  798.     }
  799.     
  800.     //    Other board is Nickstar (----) [black] millo (1705) rated wild(24) 4 4
  801.     i = 0;
  802.     if (looking_at(s, &i, "Other board is * (*) [*]")) {
  803.         if (gPrefs.autoBug) {
  804.             if (star_match[2][0] == 'b')    // auto-flip their board
  805.                 bprintf("multi flip;observe %s;flip\n", star_match[0]);
  806.             else
  807.                 bprintf("observe %s\n", star_match[0]);
  808.             return false;
  809.         }
  810.     }
  811.  
  812.     
  813.         /* Improved generic end-of-game messages */
  814.     i = 0;
  815.     if (looking_at(s, &i, "{Game * (* vs. *) *} *")) {
  816.         /* star_match[0] is the game number */
  817.         /*           [1] is the white player's name */
  818.         /*           [2] is the black player's name */
  819.         /*           [3] is the reason for the game end */
  820.         /*           [4] is a PGN end game-token */
  821.         int gamenum = atoi(star_match[0]);
  822.         char *why = star_match[3];
  823.     //    char *endtoken = star_match[4];
  824.     //    ChessMove endtype = (ChessMove) 0;
  825.  
  826.         Game *game = FindGameNum(gamenum);
  827.         if (game) {
  828.             game->jexiste = false;
  829.             game->number = -1;        // officially, we don't know about this game
  830.             strncpy(game->endReason, why, 63);        // please to remember
  831.             game->endReason[63] = 0;
  832.             DrawGameHeader(game);
  833.         }
  834.         return false;
  835.     }
  836.     
  837.         // bughouse stuff
  838.     // <b1> game 156 white [PPNNB] black [B]
  839.     i = 0;
  840.     if (looking_at(s, &i, "<b1> game * white [*] black [*]")) {
  841.         int gamenum = atoi(star_match[0]);
  842.         char *resw = star_match[1], *resb = star_match[2];
  843.  
  844.         Game *game = FindGameNum(gamenum);
  845.         if (game) {
  846.             if (!game->bug)
  847.                 MakeBughouse(game);
  848.             String2Reserves(resw, game->reserves[kWhite]);
  849.             String2Reserves(resb, game->reserves[kBlack]);
  850.             DrawReserves(game);
  851.         }
  852.         return true;
  853.     }
  854.     
  855.         /* Start/end-of-game messages */
  856. //    i = 0;
  857. //    if (looking_at(s, &i, "{Game * (* vs. *)* * *}")) {
  858.         /* Generic game start/end messages */
  859.         /* star_match[0] is the game number */
  860.         /*           [1] is the white player's name */
  861.         /*           [2] is the black player's name */
  862.         /*           [3] is either ":" or empty (don't care) */
  863.         /*           [4] is usually the loser's name or a noise word */
  864.         /*           [5] contains the reason for the game end */
  865. /*        int gamenum = atoi(star_match[0]);
  866.         char *white = star_match[1];
  867.         char *black = star_match[2];
  868.         char *loser = star_match[4];
  869.         char *why = star_match[5];
  870.         
  871.         if (strcmp(loser, "Creating") == 0 ||
  872.             strcmp(loser, "Continuing") == 0) {
  873.             Game *game = FindGameNum(gamenum);
  874.             if (!game) {
  875.                 game = NewGame(white, black, gamenum);
  876.                 return false;
  877.             }
  878.         }
  879.     }
  880. */
  881.  
  882.     i = 0;
  883.     if (looking_at(s, &i, "Removing game * from observation")) {
  884.         int gamenum = atoi(star_match[0]);
  885.         Game *game = FindGameNum(gamenum);
  886.         if (game) {
  887.             game->jexiste = false;
  888.             game->number = -1;        // officially, we don't know about this game
  889.             if (gPrefs.smartClose)
  890.                 CloseGameWindow((WindowPtr) game->wind);
  891.         }
  892.         return false;
  893.     }
  894.  
  895.     i = 0;
  896.     if (looking_at(s, &i, "You are no longer examining game *.")) {
  897.         int gamenum = atoi(star_match[0]);
  898.         Game *game = FindGameNum(gamenum);
  899.         if (game) {
  900.             game->jexiste = false;
  901.             game->number = -1;        // officially, we don't know about this game
  902.             if (gPrefs.smartClose)
  903.                 CloseGameWindow((WindowPtr) game->wind);
  904.         }
  905.         return false;
  906.     }
  907.     
  908.         // check for swearwords
  909.         // f*ck sh*t d*mn *ss b*stard
  910.         // for admins only
  911.     i = 0;
  912.     if (gPrefs.trueColors && gPrefs.adminColors) {
  913.         if (strstr(s, "fuck") || strstr(s, "shit") || strstr(s, " ass ") ||
  914.                 strstr(s, " bastard ") || strstr(s, "damn") || 
  915.                 strstr(s, "FUCK") || strstr(s, "SHIT") || strstr(s, " ASS ") ||
  916.                 strstr(s, " BASTARD ") || strstr(s, "DAMN") ||
  917.                 strstr(s, "Fuck") || strstr(s, "Shit") || strstr(s, " Ass ") ||
  918.                 strstr(s, " Bastard ") || strstr(s, "Damn")) {
  919.             PrintStringStyle(s, &swearStyle);
  920.             return true;
  921.         }
  922.     }
  923.  
  924.     return false;
  925. }
  926.  
  927.  
  928.     // watch for data coming in from server on given stream
  929. void
  930. ScanIncomingServer(short stream)
  931. {
  932.     uchar *mybuf = buf[stream];
  933.     
  934.     verify(stream < kMaxStreams);
  935.     
  936.     if (bufdata[stream] == 0)
  937.         return;        // nothing to read
  938.         
  939.     short dataUsed = 0;
  940.  
  941.     verify(bufdata[stream] > 0);
  942.     verify(bufdata[stream] < 32000);
  943.  
  944.         // just print it out for now
  945.     short i;
  946.     mybuf[bufdata[stream]] = 0;
  947. /*    for (i=0;i<bufdata[stream];i++) {
  948.         if (mybuf[i] == '\f' || mybuf[i] == '\n')
  949.             mybuf[i] = ' ';
  950.         if (mybuf[i] > 0x80)
  951.             mybuf[i] = ' ';
  952.     }
  953. */
  954.     gInTheThick = true;        // makes printing text faster -- adjust text at end only
  955.     
  956.     for (i=0;i<bufdata[stream];i++)
  957.         if (mybuf[i] == '\a' || mybuf[i] == '\f' ||
  958.                 mybuf[i] == '\n' || mybuf[i] > 0x80 || mybuf[i] == 0x01) {
  959.                 // we don't want this character, slide everything else down
  960.             short xxx;
  961.             for (xxx=i+1;xxx<bufdata[stream]+1;xxx++)
  962.                 mybuf[xxx-1] = mybuf[xxx];
  963.             bufdata[stream]--;
  964.             i--;
  965.         }
  966.     if (bufdata[stream] == 0)
  967.         return;
  968.         
  969.         // go through all the 
  970.     char *sting = (char *) mybuf;
  971.     short loop = 0, len = bufdata[stream], tot = 0;
  972.     while (tot < len) {
  973.         if (sting[loop] == '\r') {
  974.             loop++; tot++;
  975.             char c = sting[loop];
  976.             sting[loop] = 0;
  977.             if (!ParseInput(sting))
  978.                 tprintf("%s", sting);
  979.             sting = &sting[loop];
  980.             *sting = c;
  981.             dataUsed += loop;
  982.             loop = 0;
  983.         }
  984.         else {
  985.             loop++; tot++;
  986.         }
  987.     }
  988. //    DebugStr((char *) mybuf);
  989. //    dataUsed = bufdata[stream];
  990.  
  991.         // I'm really not sure what to do here
  992.         // some lines should be printed before finished, most not
  993.         // this is an ugly hack, I guess
  994.     if (!strncmp("login: ", sting, 7)) {
  995.         tprintf("%s", sting);
  996.         dataUsed = bufdata[stream];
  997.             // perform an auto-login
  998.         if (gPrefs.name[0]) {
  999.             tprintf("%s\r", gPrefs.name);
  1000.             bprintf("%s\n", gPrefs.name);
  1001.         }
  1002.     }
  1003.     if (!strncmp("password: ", sting, 10)) {
  1004.         tprintf("%s", sting);
  1005.         if (!gNeedPassword) {        // should never be true, but just in case
  1006.             bprintf("\n");        // like hit return to enter as . . .
  1007.             PrintConnectString();
  1008.         }
  1009.         else if (gPrefs.password[0]) {
  1010.             bprintf("%s\n", gPrefs.password);
  1011.             PrintConnectString();
  1012.             tprintf("{Fixation sending password automatically}");
  1013.         }
  1014.         tprintf("\r");
  1015.         gSetStyle = true;
  1016.         dataUsed = bufdata[stream];
  1017.     }
  1018.     if (gCaughtPrompt) {
  1019.         len = strlen(gPrompt);
  1020.         while (!strncmp(gPrompt, sting, len)
  1021.                 && bufdata[stream] - dataUsed >= len) {
  1022.             char c = sting[len];
  1023.             sting[len] = 0;
  1024.             tprintf("%s", sting);
  1025.             dataUsed += len;
  1026.             sting[len] = c;
  1027.             sting = &sting[len];
  1028.             if (!gSetStyle) {
  1029.                 gSetStyle = true;
  1030.                 PrintConnectString();
  1031.             }
  1032.         }
  1033.     }
  1034.  
  1035.     verify(dataUsed >= 0);
  1036.     verify(dataUsed <= bufdata[stream]);
  1037.     
  1038.         // slide the buffer down
  1039.     if (dataUsed > 0) {
  1040.         short nnn;
  1041.         bufdata[stream] -= dataUsed;
  1042.         for (nnn=0;nnn<bufdata[stream];nnn++)
  1043.             mybuf[nnn] = mybuf[nnn+dataUsed];
  1044.     }
  1045.     
  1046.         // if our connection is closed and there's extra
  1047.         // data in the buffer, flush it -- it isn't a full command
  1048.         // this will probably never be actualized because of the
  1049.         // way the TCP shit works
  1050.     if (nexStatus[stream] == kStatClosed)
  1051.         bufdata[stream] = 0;
  1052.         
  1053.     gInTheThick = false;
  1054.     CalcVBar();
  1055. }